﻿using System;
using System.Windows;

namespace Mp3Observer.Common.Factory
{
    /// <summary>
    /// This class loads the Factory from the FactoryType, creates an instance of it of type IFactory and
    /// sets it to the datacontext of the caller.
    /// </summary>
    public sealed class ViewModelLoader
    {
        #region FactoryType

        /// <summary>
        /// FactoryType Attached Dependency Property
        /// </summary>
        public static readonly DependencyProperty FactoryTypeProperty =
            DependencyProperty.RegisterAttached("FactoryType", typeof(Type), typeof(ViewModelLoader),
                new FrameworkPropertyMetadata((Type)null,
                    new PropertyChangedCallback(OnFactoryTypeChanged)));

        /// <summary>
        /// Prevents a default instance of the <see cref="ViewModelLoader"/> class from being created.
        /// </summary>
        private ViewModelLoader()
        {
        }

        /// <summary>
        /// Gets the type of the factory.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <returns>the Factory Type</returns>
        public static Type GetFactoryType(DependencyObject dependencyObject)
        {
            return (Type)dependencyObject.GetValue(FactoryTypeProperty);
        }

        /// <summary>
        /// Sets the type of the factory.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="value">The value.</param>
        public static void SetFactoryType(DependencyObject dependencyObject, Type value)
        {
            dependencyObject.SetValue(FactoryTypeProperty, value);
        }

        /// <summary>
        /// Handles changes to the FactoryType property.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnFactoryTypeChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            var element = (FrameworkElement)dependencyObject;
            IFactory factory = Activator.CreateInstance(GetFactoryType(dependencyObject)) as IFactory;
            if (factory == null)
                throw new InvalidOperationException("You have to specify a type that inherits from IFactory");
            element.DataContext = factory.CreateViewModel(dependencyObject);
        }

        #endregion
    }
}
